package com.wdl.datarest.implementation;

import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;

import com.wdl.datarest.data.SleepMode;

/**
 * One cache data size is 1 + 1 + 1 + 1 + 1 = 5 bytes
 * At most 100000 devices, 100000 * 5 = 0.5M
 */
public class CacheData {
    long deviceIndex;
    long personId;
    String deviceId;
    long deviceUpdateTime;
    short hbUpperTH;
    short hbLowerTH;
    short brUpperTH;
    short brLowerTH;
    short bodyMoveTH;
    boolean enableHbAlarm;
    boolean enableBrAlarm;
    boolean enableUpAlarm;
    boolean enableEdgeAlarm;
    boolean enableAwayAlarm;
    boolean syncedToDev;
    boolean sentReminder;

    // Used to record regular counting per hour.
    // Will be reset to 0 in hourly tasks!
    short moveTotal = 0;

    // Used to save each move for 24 hours, the time is in ms.
    CopyOnWriteArrayList<Long> moves = new CopyOnWriteArrayList<Long>();

    int heartSum = 0;
    short heartTotal = 0;

    int breatheSum = 0;
    short breatheTotal = 0;

    // in seconds
    short deepSleepInSeconds = 0;
    short shallowSleepInSeconds = 0;

    SleepMode sleepMode = SleepMode.AWAKE;
    // in ms
    long sleepModeStartingTime = 0;

    public long getDeviceIndex() {
        return deviceIndex;
    }

    public void setDeviceIndex(long deviceIndex) {
        this.deviceIndex = deviceIndex;
    }

    public String getDeviceId() {
        return deviceId;
    }

    public void setDeviceId(String deviceId) {
        this.deviceId = deviceId;
    }

    public long getPersonId() {
        return this.personId;
    }

    public void setPersonId(long personId) {
        this.personId = personId;
    }

    public long getDeviceUpdateTime() {
        return deviceUpdateTime;
    }

    public void setDeviceUpdateTime(long deviceUpdateTime) {
        this.deviceUpdateTime = deviceUpdateTime;
    }

    public short getHbUpperTH() {
        return hbUpperTH;
    }

    public void setHbUpperTH(short hbUpperTH) {
        this.hbUpperTH = hbUpperTH;
    }

    public short getHbLowerTH() {
        return hbLowerTH;
    }

    public void setHbLowerTH(short hbLowerTH) {
        this.hbLowerTH = hbLowerTH;
    }

    public short getBrUpperTH() {
        return brUpperTH;
    }

    public void setBrUpperTH(short brUpperTH) {
        this.brUpperTH = brUpperTH;
    }

    public short getBrLowerTH() {
        return brLowerTH;
    }

    public void setBrLowerTH(short brLowerTH) {
        this.brLowerTH = brLowerTH;
    }

    public short getBodyMoveTH() {
        return bodyMoveTH;
    }

    public void setBodyMoveTH(short bodyMoveTH) {
        this.bodyMoveTH = bodyMoveTH;
    }

    public boolean getEnableHbAlarm() {
        return enableHbAlarm;
    }

    public boolean isSentReminder() {
        return sentReminder;
    }

    public void setSentReminder(boolean sentReminder) {
        this.sentReminder = sentReminder;
    }

    public void setEnableHbAlarm(boolean enableHbAlarm) {
        this.enableHbAlarm = enableHbAlarm;
    }

    public boolean getEnableBrAlarm() {
        return enableBrAlarm;
    }

    public void setEnableBrAlarm(boolean enableBrAlarm) {
        this.enableBrAlarm = enableBrAlarm;
    }

    public boolean getEnableUpAlarm() {
        return enableUpAlarm;
    }

    public void setEnableUpAlarm(boolean enableUpAlarm) {
        this.enableUpAlarm = enableUpAlarm;
    }

    public boolean getEnableEdgeAlarm() {
        return enableEdgeAlarm;
    }

    public void setEnableEdgeAlarm(boolean enableEdgeAlarm) {
        this.enableEdgeAlarm = enableEdgeAlarm;
    }

    public boolean getEnableAwayAlarm() {
        return enableAwayAlarm;
    }

    public void setEnableAwayAlarm(boolean enableAwayAlarm) {
        this.enableAwayAlarm = enableAwayAlarm;
    }

    public boolean getSyncedToDev() {
        return syncedToDev;
    }

    public void setSyncedToDev(boolean syncedToDev) {
        this.syncedToDev = syncedToDev;
    }

    public int getHeartSum() {
        return heartSum;
    }

    public short getHeartTotal() {
        return heartTotal;
    }

    public void resetHeart() {
        this.heartTotal = 0;
        this.heartSum = 0;
    }

    public void increaseHeart(int heart) {
        if (heart > 0) {
            this.heartSum += heart;
            this.heartTotal++;
        }
    }

    public int getBreatheSum() {
        return breatheSum;
    }

    public short getBreatheTotal() {
        return breatheTotal;
    }

    public void resetBreathe() {
        this.breatheTotal = 0;
        this.breatheSum = 0;
    }

    public void inscreaseBreathe(int breathe) {
        if (breathe > 0) {
            this.breatheSum += breathe;
            this.breatheTotal++;
        }
    }

    public short getDeepSleepInSeconds() {
        return deepSleepInSeconds;
    }

    /**
     * Includes the last deep sleep time if the current sleep mode matches.
     */
    public short calDeepSleepInSeconds() {
        if (this.sleepMode == SleepMode.HEAVY) {
            this.increaseDeepSleep();
            this.setSleepModeStartingTime(System.currentTimeMillis());
        }
        return deepSleepInSeconds;
    }

    public void setDeepSleepInSeconds(short deepSleep) {
        this.deepSleepInSeconds = deepSleep;
    }

    public short getShallowSleepInSeconds() {
        return shallowSleepInSeconds;
    }

    /**
     * Includes the last shallow sleep time if the current sleep mode matches.
     */
    public short calShallowSleepInSeconds() {
        if (this.sleepMode == SleepMode.LIGHT) {
            this.increaseShallowSleep();
            this.setSleepModeStartingTime(System.currentTimeMillis());
        }
        return shallowSleepInSeconds;
    }

    public void setShallowSleepInSeconds(short shallowSleep) {
        this.shallowSleepInSeconds = shallowSleep;
    }

    public SleepMode getSleepMode() {
        return sleepMode;
    }

    public void setSleepMode(SleepMode sleepMode) {
        this.sleepMode = sleepMode;
    }

    public long getSleepModeStartingTime() {
        return sleepModeStartingTime;
    }

    public void setSleepModeStartingTime(long sleepModeStartingTime) {
        this.sleepModeStartingTime = sleepModeStartingTime;
    }

    public void increaseDeepSleep() {
        if (this.sleepModeStartingTime > 0 && System.currentTimeMillis() > this.sleepModeStartingTime) {
            this.deepSleepInSeconds += (short) Math.round((System.currentTimeMillis() - this.sleepModeStartingTime) / 1000);
        }
    }

    public void increaseShallowSleep() {
        if (this.sleepModeStartingTime > 0 && System.currentTimeMillis() > this.sleepModeStartingTime) {
            this.shallowSleepInSeconds += (short) Math.round((System.currentTimeMillis() - this.sleepModeStartingTime) / 1000);
        }
    }

    public short getMoveTotal() {
        return moveTotal;
    }

    public short getBodyMoveDelta(long passedTime) {
        short count = 0;
        long startingTime = System.currentTimeMillis() - passedTime;
        Iterator<Long> iterator = moves.iterator();
        while (iterator.hasNext()) {
            long raisedTime = iterator.next();
            if (raisedTime > startingTime) {
                count++;
            }
        }
        return count;
    }

    public void increaseMoveTotal() {
        this.moveTotal++;

        // Remove movements earlier than 24 hours.
        long retaintionTime = System.currentTimeMillis() - 24 * 60 * 60 * 1000;
        Iterator<Long> iterator = moves.iterator();
        while (iterator.hasNext()) {
            long raisedTime = iterator.next();
            if (raisedTime < retaintionTime) {
                moves.remove(raisedTime);
            }
        }

        // save this movement into cache
        this.moves.add(System.currentTimeMillis());
    }

    public void resetMoveTotal() {
        this.moveTotal = 0;
    }

    public CopyOnWriteArrayList<Long> getMoves() {
        return moves;
    }

    public void setMoveTotal(short moveTotal) {
        this.moveTotal = moveTotal;
    }

    @Override
    public String toString() {
        return  "deviceIndex=" + deviceIndex + ", deviceId=" + deviceId + ", deviceUpdateTime=" + deviceUpdateTime + ", personId=" + personId +
                ", hbUpperTH=" + hbUpperTH + ", hbLowerTH=" + hbLowerTH + ", brUpperTH=" + brUpperTH + ", brLowerTH=" + brLowerTH +
                ", bodyMoveTH=" + bodyMoveTH + ", enableHbAlarm=" + enableHbAlarm + ", enableBrAlarm=" + enableBrAlarm +
                ", enableUpAlarm=" + enableUpAlarm + ", enableEdgeAlarm=" + enableEdgeAlarm + ", enableAwayAlarm=" + enableAwayAlarm +
                ", syncedToDev=" + syncedToDev;
    }
}